﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace YServer
{
    public class YToken
    {
        /// <summary>
        /// 读、取异步套接字操作
        /// </summary>
        public SocketAsyncEventArgs r_SAEArgs, w_SAEArgs;

        /// <summary>
        /// 此连接中的套接字对象
        /// </summary>
        public Socket socket;

        /// <summary>
        /// 消息处理中心
        /// </summary>
        public AbsHandlerCenter center;

        //读取消息的缓存
        List<byte> cache=new List<byte>();

        //写消息的字节队列
        Queue<byte[]> write_queue = new Queue<byte[]>();

        /// <summary>
        /// 消息长度解码委托
        /// </summary>
        public LengthDe_de LD;
        /// <summary>
        /// 消息长度编码委托
        /// </summary>
        public LengthEn_de LE;

        /// <summary>
        /// 传输模型解码委托
        /// </summary>
        public SocketModelDe_de SD;
        /// <summary>
        /// 传输模型编码委托
        /// </summary>
        public SocketModelEn_de SE;

        public delegate void SendProcessAsync(SocketAsyncEventArgs e);
        public delegate void CloseProcess(YToken token,string t);

        public SendProcessAsync sendProcess;
        public CloseProcess closeProcess;

        bool isWrite, isRead;

        public YToken() {
            r_SAEArgs = new SocketAsyncEventArgs();
            w_SAEArgs = new SocketAsyncEventArgs();

            r_SAEArgs.SetBuffer(new byte[1024], 0, 1024);
            //w_SAEArgs.SetBuffer(new byte[1024], 0, 1024); 写操作此时不必分配内存

            r_SAEArgs.UserToken = this;
            w_SAEArgs.UserToken = this;
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="byte_cache"></param>
        public void Receive(byte[] byte_cache) {

            //向 缓冲区 cache 添加接收的字节数据
            cache.AddRange(byte_cache);
            if (!isRead) {
                isRead = true;
                Read();
            }

        }

        /// <summary>
        /// 对缓冲区数据进行处理
        /// </summary>
        void Read()
        {
            //TODO 粘包处理
            if (LD != null) {
                byte[] result;
                result= LD(ref cache);

                //如果 result 为 null ，数据尚未足够，返回
                if (result == null) { isRead = false; return; }

                //否则，进行消息的解码（socketmodel）
                SocketModel model = (SocketModel)SD(result);

                //TODO 通知上层应用消息到达，并进行逻辑分发
                center.OnClientMessage(this, model);

                //递归处理剩余数据
                Read();
            }

        }

        public void Send(SocketModel model)
        {
            //对传输数据模型编码 socketmodel
            byte[] result = SE(model);
            //对数据进行长度编码
            result = LE(result);

            write_queue.Enqueue(result);

            if (!isWrite)
            {
                isWrite = true;
                Write();
            }
        }

        public void Write()
        {
            if (write_queue.Count == 0)
            {
                isWrite = false;
                return;
            }

            //消息队列不为空，取出来并发送
            byte[] queue = write_queue.Dequeue();

            //为异步操作设置数据缓冲（已绑定上层Y_Server中的 IO_Completed）
            w_SAEArgs.SetBuffer(queue, 0, queue.Length);

            //开始异步发送消息
            bool result = socket.SendAsync(w_SAEArgs);

            //没有挂起，则直接调用 sendProcess 委托（已绑定 Y_Server中的ProcessSend 循环发送）
            //若挂起了，异步操作完成后会调用Y_Server中的 IO_Completed，最终执行 ProcessSend
            if (!result) { sendProcess(w_SAEArgs); }

        }
        /// <summary>
        /// 关闭 socket 清空各种缓冲数据
        /// </summary>
        public void Close() {
            try
            {
                cache.Clear();

                //close 前先 shutdown
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
                socket = null;
            }
            catch (Exception ex) {
                Console.WriteLine(ex.ToString());
            }
        }


    }
}
